/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.editor.ext; import java.util.ArrayList; import javax.swing.text.BadLocationException; import org.netbeans.editor.BaseDocument; import org.netbeans.editor.EditorDebug; /** * Expression generated by parsing text by java completion * * @author Miloslav Metelka * @version 1.00 */ public class JCExpression { /** Invalid expression - this ID is used only internally */ private static final int INVALID = -1; /** Constant - int/long/String/char etc. */ public static final int CONSTANT = 0; /** Variable 'a' or 'a.b.c' */ public static final int VARIABLE = 1; /** Operator '+' or '--' */ public static final int OPERATOR = 2; /** Special value for unary operators */ public static final int UNARY_OPERATOR = 3; /** Dot between method calls 'a().b()' or 'a().b.c.d(e, f)' */ public static final int DOT = 4; /** Dot between method calls and dot at the end 'a().b().' or 'a().b.c.d(e, f).' */ public static final int DOT_OPEN = 5; /** Opened array 'a[0' or 'a.b.c[d.e' */ public static final int ARRAY_OPEN = 6; /** Array 'a[0]' or 'a.b.c[d.e]' */ public static final int ARRAY = 7; /** Left opened parentheses */ public static final int PARENTHESIS_OPEN = 8; /** Closed parenthesis holding the subexpression or conversion */ public static final int PARENTHESIS = 9; /** Opened method 'a(' or 'a.b.c(d, e' */ public static final int METHOD_OPEN = 10; /** Method closed by right parentheses 'a()' or 'a.b.c(d, e, f)' */ public static final int METHOD = 11; /** Constructor closed by right parentheses 'new String()' or 'new String("hello")' */ // NOI18N public static final int CONSTRUCTOR = 12; /** Conversion '(int)a.b()' */ public static final int CONVERSION = 13; /** Data type */ public static final int TYPE = 14; /** 'new' keyword */ public static final int NEW = 15; /** 'instanceof' operator */ public static final int INSTANCEOF = 16; /** Constant to add to expression ID to convert * it to operator. */ private static final int EXP_ID_START = 50; /** Array that holds the priority, associativity * and other info about operators. The first part * is reserved for operator IDs as defined in JavaSyntax. * The rest is used for expression IDs. */ private static final int[] OP = new int[70]; /** Is the operator right associative? */ private static final int RIGHT_ASSOCIATIVE = 32; static { OP[JavaSyntax.EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.LT] = 10; OP[JavaSyntax.GT] = 10; OP[JavaSyntax.LLT] = 11; OP[JavaSyntax.GGT] = 11; OP[JavaSyntax.GGGT] = 11; OP[JavaSyntax.PLUS] = 12; OP[JavaSyntax.MINUS] = 12; OP[JavaSyntax.MUL] = 13; OP[JavaSyntax.DIV] = 13; OP[JavaSyntax.AND] = 8; OP[JavaSyntax.OR] = 6; OP[JavaSyntax.XOR] = 7; OP[JavaSyntax.MOD] = 13; OP[JavaSyntax.NOT] = 14; OP[JavaSyntax.NEG] = 14; OP[JavaSyntax.EQ_EQ] = 9; OP[JavaSyntax.LE] = 10; OP[JavaSyntax.GE] = 10; OP[JavaSyntax.LLE] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.GGE] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.GGGE] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.PLUS_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.MINUS_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.MUL_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.DIV_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.AND_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.OR_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.XOR_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.MOD_EQ] = 2 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.NOT_EQ] = 9; OP[JavaSyntax.DOT] = 15; OP[JavaSyntax.COLON] = 3 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.QUESTION] = 3 | RIGHT_ASSOCIATIVE; OP[JavaSyntax.LEFT_SQUARE_BRACKET] = 15; OP[JavaSyntax.RIGHT_SQUARE_BRACKET] = 0; // stop OP[JavaSyntax.PLUS_PLUS] = 15; OP[JavaSyntax.MINUS_MINUS] = 15; OP[JavaSyntax.AND_AND] = 5; OP[JavaSyntax.OR_OR] = 4; OP[JavaSyntax.COMMA] = 0; // stop OP[JavaSyntax.SEMICOLON] = 0; // not-recognized OP[JavaSyntax.LEFT_PARENTHESES] = 16; OP[JavaSyntax.RIGHT_PARENTHESES] = 0; // not-recognized OP[JavaSyntax.LEFT_BRACE] = 0; // not-recognized OP[JavaSyntax.RIGHT_BRACE] = 0; // not-recognized OP[EXP_ID_START + INVALID] = 0; OP[EXP_ID_START + CONSTANT] = 1; OP[EXP_ID_START + VARIABLE] = 1; OP[EXP_ID_START + UNARY_OPERATOR] = 15; OP[EXP_ID_START + DOT] = 1; OP[EXP_ID_START + DOT_OPEN] = 0; // stop OP[EXP_ID_START + ARRAY_OPEN] = 0; // stop OP[EXP_ID_START + ARRAY] = 1; OP[EXP_ID_START + PARENTHESIS_OPEN] = 0; // stop OP[EXP_ID_START + PARENTHESIS] = 1; OP[EXP_ID_START + METHOD_OPEN] = 0; // stop OP[EXP_ID_START + METHOD] = 1; OP[EXP_ID_START + CONSTRUCTOR] = 1; OP[EXP_ID_START + CONVERSION] = 1; OP[EXP_ID_START + TYPE] = 0; // stop OP[EXP_ID_START + NEW] = 0; // stop OP[EXP_ID_START + INSTANCEOF] = 10; } private static final int[] EMPTY_INT_ARRAY = new int[0]; private static final char[] EMPTY_CHAR_ARRAY = new char[0]; private JCExpression parent; /** ID of the expression */ private int id; /** Result type */ private JCType type; /** Current token index saying how many token blocks was added * 4 */ private int tokenInd; /** token info blocks containing token ID, helper ID, * offset of the token in the buffer and the length of the token */ private int[] tokenBlocks = EMPTY_INT_ARRAY; /** List of parameters * @associates JCExpression*/ private ArrayList prmList; /** Buffer with the scanned characters */ private char[] buffer; /** Starting position of the buffer */ private int bufferStartPos; JCExpression(char[] buffer, int bufferStartPos, int id) { this.buffer = buffer; this.bufferStartPos = bufferStartPos; this.id = id; } /** Create empty variable. */ static JCExpression createEmptyVariable(int pos) { JCExpression empty = new JCExpression(EMPTY_CHAR_ARRAY, pos, VARIABLE); empty.addToken(JavaSyntax.IDENTIFIER, -1, 0, 0); return empty; } static int getOperatorID(int tokenID, int helperID) { switch (tokenID) { case JavaSyntax.OPERATOR: return helperID; case JavaSyntax.KEYWORD: switch (helperID) { case JavaKeywords.NEW: return EXP_ID_START + NEW; case JavaKeywords.INSTANCEOF: return EXP_ID_START + INSTANCEOF; default: return -1; } } return -1; } static int getOperatorID(JCExpression exp) { int expID = (exp != null) ? exp.getID() : INVALID; switch (expID) { case OPERATOR: return exp.getTokenHelperID(0); } return EXP_ID_START + expID; } static int getOperatorPrecedence(int opID) { return OP[opID] & 31; } static boolean isOperatorRightAssociative(int opID) { return (OP[opID] & RIGHT_ASSOCIATIVE) != 0; } /** Is the expression a valid type. It can be either datatype * or array. */ static boolean isValidType(JCExpression exp) { switch (exp.getID()) { case ARRAY: if (exp.getParameterCount() == 1) { return isValidType(exp.getParameter(0)); } return false; case DOT: int prmCnt = exp.getParameterCount(); for (int i = 0; i < prmCnt; i++) { if (exp.getParameter(i).getID() != VARIABLE) { return false; } } return true; case TYPE: case VARIABLE: return true; } return false; } public int getID() { return id; } void setID(int id) { this.id = id; } public JCExpression getParent() { return parent; } void setParent(JCExpression parent) { this.parent = parent; } public JCType getType() { return type; } void setType(JCType type) { this.type = type; } public int getTokenCount() { return tokenInd / 4; } public int[] getTokenBlocks() { return tokenBlocks; } public String getTokenText(int tokenInd) { tokenInd *= 4; return new String(buffer, tokenBlocks[tokenInd + 2], tokenBlocks[tokenInd + 3]); } public int getTokenPosition(int tokenInd) { tokenInd *= 4; return bufferStartPos + tokenBlocks[tokenInd + 2]; } public int getTokenLength(int tokenInd) { tokenInd *= 4; return tokenBlocks[tokenInd + 3]; } public int getTokenID(int tokenInd) { tokenInd *= 4; return tokenBlocks[tokenInd]; } public int getTokenHelperID(int tokenInd) { tokenInd *= 4; return tokenBlocks[tokenInd + 1]; } char[] getBuffer() { return buffer; } int getBufferStartPosition() { return bufferStartPos; } void addToken(int tokenID, int helperID, int offset, int len) { if (tokenInd == tokenBlocks.length) { int[] tmp = new int[Math.max(4, tokenBlocks.length * 2)]; if (tokenBlocks.length > 0) { System.arraycopy(tokenBlocks, 0, tmp, 0, tokenBlocks.length); } tokenBlocks = tmp; } tokenBlocks[tokenInd++] = tokenID; tokenBlocks[tokenInd++] = helperID; tokenBlocks[tokenInd++] = offset; tokenBlocks[tokenInd++] = len; } public int getParameterCount() { return (prmList != null) ? prmList.size() : 0; } public JCExpression getParameter(int index) { return (JCExpression)prmList.get(index); } void addParameter(JCExpression prm) { if (prmList == null) { prmList = new ArrayList(); } prm.setParent(this); prmList.add(prm); } void swapOperatorParms() { if ((id == OPERATOR || id == INSTANCEOF) && getParameterCount() == 2) { JCExpression exp1 = (JCExpression)prmList.remove(0); prmList.add(exp1); exp1.swapOperatorParms(); ((JCExpression)prmList.get(0)).swapOperatorParms(); } } private String getIndent(int indent) { StringBuffer sb = new StringBuffer(); while (indent-- > 0) { sb.append(' '); } return sb.toString(); } static String getIDName(int id) { switch (id) { case CONSTANT: return "CONSTANT"; // NOI18N case VARIABLE: return "VARIABLE"; // NOI18N case OPERATOR: return "OPERATOR"; // NOI18N case UNARY_OPERATOR: return "UNARY_OPERATOR"; // NOI18N case DOT: return "DOT"; // NOI18N case DOT_OPEN: return "DOT_OPEN"; // NOI18N case ARRAY: return "ARRAY"; // NOI18N case ARRAY_OPEN: return "ARRAY_OPEN"; // NOI18N case PARENTHESIS_OPEN: return "PARENTHESIS_OPEN"; // NOI18N case PARENTHESIS: return "PARENTHESIS"; // NOI18N case METHOD_OPEN: return "METHOD_OPEN"; // NOI18N case METHOD: return "METHOD"; // NOI18N case CONSTRUCTOR: return "CONSTRUCTOR"; // NOI18N case CONVERSION: return "CONVERSION"; // NOI18N case TYPE: return "TYPE"; // NOI18N case NEW: return "NEW"; // NOI18N case INSTANCEOF: return "INSTANCEOF"; // NOI18N default: return "Unknown id " + id; // NOI18N } } public String toString(int indent) { String indentStr = getIndent(indent); StringBuffer sb = new StringBuffer(); sb.append("id=" + getIDName(id)); // NOI18N if (type != null) { sb.append(", result type="); // NOI18N sb.append(type); } // Debug tokens int tokenCnt = getTokenCount(); int[] blocks = getTokenBlocks(); sb.append(", token count="); // NOI18N sb.append(tokenCnt); if (tokenCnt > 0) { for (int i = 0; i < tokenInd;) { int tokenID = blocks[i++]; int helperID = blocks[i++]; int offset = blocks[i++]; int len = blocks[i++]; sb.append(", token" + (i / 4 - 1) + "='" + EditorDebug.debugChars(buffer, offset, len) + "'"); // NOI18N } } // Debug parameters int parmCnt = getParameterCount(); sb.append(", parm count="); // NOI18N sb.append(parmCnt); if (parmCnt > 0) { for (int i = 0; i < parmCnt; i++) { sb.append('\n'); sb.append(indentStr); sb.append("parm" + i + "=[" + getParameter(i).toString(indent + 2) + "]"); // NOI18N } } return sb.toString(); } public String toString() { return toString(0); } } /* * Log * 8 Gandalf 1.7 1/13/00 Miloslav Metelka Localization * 7 Gandalf 1.6 12/28/99 Miloslav Metelka * 6 Gandalf 1.5 11/14/99 Miloslav Metelka * 5 Gandalf 1.4 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 4 Gandalf 1.3 10/10/99 Miloslav Metelka * 3 Gandalf 1.2 10/4/99 Miloslav Metelka * 2 Gandalf 1.1 9/30/99 Miloslav Metelka * 1 Gandalf 1.0 9/15/99 Miloslav Metelka * $ */